/**
 * Copyright (c) 2010 sonntagsfarben.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package de.sonntagsfarben.logger
{
	import de.sonntagsfarben.logger.output.*;

	import flash.utils.getDefinitionByName;

	/**
	 * @author Soenke Kluth <kluth@sonntagsfarben.de>
	 * @copyright (c) 2009 Soenke Kluth.
	 */
	public class SFLogger
	{
		public static const VERSION : String = "0.9";
		//
		public static const ALL : String = "SFLogger.ALL";
		//
		public static const DEBUG : String = "DEBUG";
		public static const INFO : String = "INFO";
		public static const WARN : String = "WARN";
		public static const ERROR : String = "ERROR";
		public static const FATAL : String = "FATAL";
		//
		private static var _initialzed : Boolean;
		private static var _enabled : Boolean = false;
		private static var _showLineNumbers : Boolean;
		private static var _lineCounter : uint;
		//
		private static var _output : ILogOutput = new TraceLogOutput();
		private static var _loggerName : String = "";

		//private static var _exculdeMap:Dictionary = new Dictionary();
		public static function initialize(name : String = "", output : ILogOutput = null, showLineNumber : Boolean = true) : void
		{
			if (_initialzed)
			{
				trace(WARN + ": " + SFLogger + " :: already initialized");
				return;
			}
			_output = (output) ? output : _output;
			_initialzed = true;
			_enabled = true;
			_loggerName = name;
			_showLineNumbers = showLineNumber;
		}

		
		//TODO regexp benutzen!!!!
		private static function get target() : Object
		{
			var object : Object;
			var method : String;

			try {
				var str : String = new Error().getStackTrace();
				str = str.split("\n").join("");
				str = str.split("\t").join("");

				var neededClassString : String = str.split("]")[3];
				neededClassString = neededClassString.split("at ").join("");
				neededClassString = neededClassString.split("[")[0];
				neededClassString = neededClassString.split("::").join(".");

				if (neededClassString.indexOf("$/") > -1)
				{
					//isStatic
					method = neededClassString.substr(neededClassString.lastIndexOf("/") + 1, neededClassString.lastIndexOf("("));
					method = "$" + method;
					neededClassString = neededClassString.split("$")[0];
					object = getDefinitionByName(neededClassString);
				}
				else if (neededClassString.match("/") == null)
				{
					//isConstriuctor
					method = neededClassString.substr(neededClassString.lastIndexOf(".") + 1, neededClassString.lastIndexOf("("));
					neededClassString = neededClassString.split("()").join("");
					object = getDefinitionByName(neededClassString);
				}
				else
				{
					//isMethod
					method = neededClassString.substr(neededClassString.lastIndexOf("/") + 1, neededClassString.lastIndexOf("("));
					neededClassString = neededClassString.split("/")[0];
					object = getDefinitionByName(neededClassString);
				}

				++_lineCounter;
				return ({object:object, method:method});
			}
			catch (e : Error) {
				trace("SFLogger::: muss noch anonymus implementieren!! " + e.message);
				return ({object:null, method:null});
			}
			return ({object:null, method:null});
		}

		
		private static function _log(logLevel : String, log : *) : void
		{
			var tgt : Object = SFLogger.target;
			SFLogger._output.log(logLevel, tgt["object"], tgt["method"], log);
		}

		
		private static function validate(name : String) : Boolean
		{
			if(!_enabled)
				return false;
			if(name != _loggerName && name != SFLogger.ALL)
			{
				return false;
			}
			return true;
		}

		
		//just to keep it compatible with older projects
		public static function log(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			SFLogger._log(DEBUG, log);
		}

		
		public static function debug(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			SFLogger._log(DEBUG, log);
		}

		
		public static function error(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			SFLogger._log(ERROR, log);
		}

		
		public static function warn(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			SFLogger._log(WARN, log);
		}

		
		public static function fatal(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			SFLogger._log(FATAL, log);
		}

		
		public static function dump(log : *, name : String = "") : void
		{
			if(!validate(name)) return;
			//getDefinitionByName("mx.utils.ObjectUtil");
			trace("DUMP :: Write something like ObjectUtil " + log);
		}

		
		public static function addOutput(output : ILogOutput) : void
		{
			if (!(_output is MultipleLogOutput))
			{
				var outp : MultipleLogOutput = new MultipleLogOutput([outp]);
				outp.add(outp);
				outp.add(output);
			}
			else
			{
				(_output as MultipleLogOutput).add(output);
			}
		}

		
		public static function removeOutput(output : ILogOutput) : void
		{
			if (_output is MultipleLogOutput)
			{
				(_output as MultipleLogOutput).remove(output);
			}
		}

		
		public static function get output() : ILogOutput
		{
			return SFLogger._output;
		}

		
		public static function disable() : void
		{
			_enabled = false;
		}

		
		public static function enable() : void
		{
			_enabled = true;
		}

		
		public static function get enabled() : Boolean
		{
			return _enabled;
		}

		
		static public function get lineCounter() : uint
		{
			return _lineCounter;
		}
	}
}
